/* Copyright (C) 2007  Felipe A. Lessa
 * Copyright (C) 2007  Renan Leandro Ferreira
 * Copyright (C) 2007  Luciano Henrique dos Santos
 * 
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 * 
 */
package tirateima.gui;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.io.Reader;

import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSlider;
import javax.swing.JSplitPane;
import javax.swing.event.AncestorEvent;
import javax.swing.event.AncestorListener;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

import tirateima.controlador.Controlador;
import tirateima.gerador.Gerador;
import tirateima.gui.arquivos.ArquivoVisivelEventListener;
import tirateima.gui.arquivos.GerenciadorArquivos;
import tirateima.gui.console.Console;
import tirateima.gui.editortexto.EditorTexto;
import tirateima.gui.variaveis.Mostrador;


/**
 * 
 * Classe principal do AlgoStep. Cria e controla todas as outras classes.
 * Deve ser incluída num applet ou numa janela para ser útil.
 *
 * @see tirateima.main.Applet
 * @see tirateima.main.Programa
 *
 */
@SuppressWarnings("serial")
public class Principal extends JPanel {
	private EditorTexto editor = null;
	private Mostrador mostrador = null;
	private JButton btnProximo = null;
	private JButton btnAnterior = null;
	private Console console = null;
	private GerenciadorArquivos ga = null;
	@SuppressWarnings("unused")
	private Controlador control = null;
	
	private JSplitPane spl_principal = null;
	private JSplitPane spl_painel_direita = null;
	private JSplitPane spl_desenho = null;
	
	/**
	 * Cria e inicializa todos os componentes.
	 */
	public Principal() {
		inicializar();
		btnAnterior.setEnabled(false);
		btnProximo.setEnabled(false);
	}
	
	/**
	 * Cria e inicializa a interface.
	 * 
	 * @param arq_fonte Streamer com o texto do arquivo fonte.
	 * @param arq_texto Streamer com o texto do arquivo de instruções.
	 * 
	 * @throws Exception
	 */
	public Principal(Reader arq_fonte, Reader arq_texto) throws Exception{		
		inicializar();
		editor.getCaixaTexto().setText(arq_fonte);
		
		Gerador gerador = new Gerador(
				mostrador,
				editor,
				console,
				ga);
		
		control = new Controlador(
				gerador.parse(arq_texto),
				mostrador,
				ga,
				editor,
				console,
				btnAnterior,
				btnProximo);
	}
	
	/**
	 * Retorna o componente mostrador.
	 */
	public Mostrador getMostrador() {
		if(mostrador == null){
			mostrador = new Mostrador();
			mostrador.setPreferredSize(new Dimension(400,400));
		}
		return mostrador;
	}
	
	/**
	 * Retorna o componente editor.
	 */
	public EditorTexto getEditor() {
		if(editor == null){
			editor = new EditorTexto();
		}
		return editor;
	}
	
	/**
	 * Retorna botão p/ estado anterior.
	 */
	public JButton getBtnAnterior(){
		if(btnAnterior == null){
			btnAnterior = new JButton("Anterior");
		}
		
		return btnAnterior;
	}
	
	/**
	 * Retorna botão p/ próximo estado.
	 */
	public JButton getBtnProximo(){
		if(btnProximo == null){
			btnProximo = new JButton("Próximo");
		}
		
		return btnProximo;
	}
	
	/**
	 * Para que seja possível tratar eventos de teclado
	 * no componente.
	 */
	public boolean isFocusable(){
		return true;
	}
	
	private void inicializar(){
		setLayout(new BorderLayout());		
		spl_principal = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true,
		                                  criarPainelDeTexto(), criarPainelDireita());
		spl_principal.setResizeWeight(0.3);
		add(spl_principal, BorderLayout.CENTER);
		
		/* Controle via setas direcionais. */
		this.addKeyListener(new KeyListener(){
			public void keyPressed(KeyEvent e){};
			
			public void keyReleased(KeyEvent e){
				switch(e.getKeyCode()){
					case KeyEvent.VK_DOWN:
					case KeyEvent.VK_RIGHT:
						btnProximo.doClick();
						break;
					case KeyEvent.VK_UP:
					case KeyEvent.VK_LEFT:
						btnAnterior.doClick();
						break;
				}
			}
			
			public void keyTyped(KeyEvent e){}
		});
		
		this.addAncestorListener(new AncestorListener(){
			public void ancestorAdded(AncestorEvent arg0) {
				spl_principal.setDividerLocation(0.3);
				spl_painel_direita.setDividerLocation(0.75);
				spl_desenho.setDividerLocation(0.7);
			}

			public void ancestorMoved(AncestorEvent arg0) {}

			public void ancestorRemoved(AncestorEvent arg0) {}
			
		});
	}
	
	private JComponent criarPainelDireita(){
		spl_painel_direita = new JSplitPane(JSplitPane.VERTICAL_SPLIT, true,
                criarAreaDeDesenho(),
                new JScrollPane(getConsole(),
            			JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
            			JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED));
		spl_painel_direita.setResizeWeight(0.75);
		spl_painel_direita.resetToPreferredSizes();
		
		console.setFont(new Font("Courier New", Font.BOLD, 14));		
		return spl_painel_direita;
	}
	
	private JPanel criarPainelDeTexto(){
		JPanel p = new JPanel(new GridBagLayout());
		GridBagConstraints gb = new GridBagConstraints();
		
		//Cria o label de título
		gb.anchor = GridBagConstraints.NORTHWEST;
		gb.fill = GridBagConstraints.HORIZONTAL;
		gb.gridx = 0;
		gb.gridy = 0;
		gb.gridwidth = 3;
		gb.gridheight = 1;
		gb.weightx = 1.0;
		gb.weighty = 0.00;
		JLabel titulo = new JLabel("Código-fonte");
		titulo.setHorizontalAlignment(JLabel.CENTER);
		titulo.setVerticalAlignment(JLabel.CENTER);
		p.add(titulo, gb);
		
		//Cria o editor de texto
		gb.gridx = 0;
		gb.gridy = 1;
		gb.gridwidth = 3;
		gb.gridheight = 1;
		gb.weightx = 1.0;
		gb.weighty = 1.0;
		gb.fill = GridBagConstraints.BOTH;
		p.add(getEditor(), gb);
		
		//Cria os dois botões
		gb.gridx = 0;
		gb.gridy = 2;
		gb.gridwidth = 1;
		gb.gridheight = 1;
		gb.weightx = 0.3;
		gb.weighty = 0.0;
		gb.fill = GridBagConstraints.BOTH;
		p.add(getBtnAnterior(), gb);
		
		gb.gridx = 2;
		gb.gridy = 2;
		p.add(getBtnProximo(), gb);
		
		return p;
	}
	
	private JPanel criarPainelMostrador(){
		JPanel modulo2 = new JPanel();
		modulo2.setLayout(new GridBagLayout());
		
		GridBagConstraints c = new GridBagConstraints();
		c.gridx = 0;
		c.gridy = 0;
		c.gridwidth = 1;
		c.fill = GridBagConstraints.BOTH;
		c.weightx = 1.0;
		c.weighty = 1.0;
		modulo2.add(getMostrador(), c);
		
		final JSlider tamanho = new JSlider(JSlider.HORIZONTAL, 1, 2000, 100);
		tamanho.addChangeListener(new ChangeListener() {
			public void stateChanged(ChangeEvent arg0) {
				int valor = tamanho.getValue();
				mostrador.setProporcao(valor / 100.0);
			}
		});
		
		c.gridy = 1;
		c.weighty = 0.0;
		modulo2.add(tamanho, c);
		
		return modulo2;
	}
	
	private JComponent criarAreaDeDesenho() {
		spl_desenho = new JSplitPane(JSplitPane.VERTICAL_SPLIT, true,
                criarPainelMostrador(), getGA());
		spl_desenho.setResizeWeight(0.7);
		spl_desenho.resetToPreferredSizes();
		return spl_desenho;
	}
	
	private GerenciadorArquivos getGA(){
		if(ga == null){
			ga = new GerenciadorArquivos();
			ga.setPreferredSize(new Dimension(400, 50));
			
			ga.addArquivoVisivelListener(new ArquivoVisivelEventListener() {

				public void ficouInvisivel() {
					spl_desenho.resetToPreferredSizes();
				}

				public void ficouVisivel() {
					spl_desenho.resetToPreferredSizes();
				}
				
			});
		}
		
		return ga;
	}
	
	private Console getConsole(){
		if(console == null){
			console = new Console();
			//console.setPreferredSize(new Dimension(400,50));
		}
		
		return console;
	}
}
